package spring.transaction;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-transaction-config.xml");
        //此时必须要获取Spring管理的实例，因为现在scope="prototype" 只有请求获取的时候才会实例化对象
        JdbcTemplate jdbcTemplate = (JdbcTemplate)context.getBean("jdbcTemplate");
        TransactionTemplate transactionTemplate= (TransactionTemplate)context.getBean("transactionTemplate");


//        String sql = "select count(*) from student";
//        int insertCount = jdbcTemplate.queryForObject(sql, new Object[] {}, Integer.class);
//        System.out.println(jdbcTemplate);

        // TransactionalTest必须得是个bean的时候才能生效，为了aop吧，有没有实现接口其实无所谓
//        TransactionalInterface transactionalTest= (TransactionalInterface)context.getBean("transactionalTest", TransactionalInterface.class);
//        transactionalTest.transactionalTest1(jdbcTemplate);

        // TransactionalTest2是个同文件的未实现接口的类，也行
        TransactionalTest2 transactionalTest2= (TransactionalTest2)context.getBean("transactionalTest2", TransactionalTest2.class);
        transactionalTest2.test(jdbcTemplate);
//        new TransactionTemplateTest().test(transactionTemplate, jdbcTemplate);

    }

    // ERROR，这个不会生效，本类通过this调用其它同类方法@Transactional无效
    @Transactional
    public void transactionalTest1(JdbcTemplate jdbcTemplate){
        String sql = "update student set group_id = 1 where id = 1";
        jdbcTemplate.update(sql);
        System.out.println("ok");
    }

}

@Component
class TransactionalTest2{

    @Transactional
    public void test(JdbcTemplate jdbcTemplate) {
        String sql = "select count(*) from student";
//                String updateSql = "update student set group_id = 12 where id = 1";
//                jdbcTemplate.update(updateSql);
        jdbcTemplate.queryForObject(sql, new Object[] {}, Integer.class);
        return;
    }
}

class TransactionTemplateTest{

    // 这种搞法有事务，update、select都有
    // transactionTemplate.execute接受一个实现了TransactionCallback的类，核心是调用它的doInTransaction，在它前后包一层事务，这里通过匿名内部类做了一个
    // 是种典型的模板方法模式
    public void test(TransactionTemplate transactionTemplate, JdbcTemplate jdbcTemplate) {
//        String sql = "select count(*) from student for update";
        transactionTemplate.execute(new TransactionCallback() {
            @Override
            public Object doInTransaction(TransactionStatus status) {
                String sql = "select count(*) from student";
//                String updateSql = "update student set group_id = 12 where id = 1";
//                jdbcTemplate.update(updateSql);
                jdbcTemplate.queryForObject(sql, new Object[] {}, Integer.class);
                return null;
            }
        });
    }
}